/**
 * created by 江心才子, 2020/4/2 0002
 * Copyright (c) 2020, 270628297@qq.com All Rights Reserved.
 * #                   *********                            #
 * #                  ************                          #
 * #                  *************                         #
 * #                 **  ***********                        #
 * #                ***  ****** *****                       #
 * #                *** *******   ****                      #
 * #               ***  ********** ****                     #
 * #              ****  *********** ****                    #
 * #            *****   ***********  *****                  #
 * #           ******   *** ********   *****                #
 * #           *****   ***   ********   ******              #
 * #          ******   ***  ***********   ******            #
 * #         ******   **** **************  ******           #
 * #        *******  ********************* *******          #
 * #        *******  ******************************         #
 * #       *******  ****** ***************** *******        #
 * #       *******  ****** ****** *********   ******        #
 * #       *******    **  ******   ******     ******        #
 * #       *******        ******    *****     *****         #
 * #        ******        *****     *****     ****          #
 * #         *****        ****      *****     ***           #
 * #          *****       ***        ***      *             #
 * #            **       ****        ****                   #
 */
package com.wyl.bluetoothapp.util

import android.app.Application
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothSocket
import android.content.IntentFilter
import com.wyl.bluetoothapp.UUID4
import com.wyl.bluetoothapp.domain.BlueInfo
import com.wyl.bluetoothapp.domain.BlueState
import com.wyl.bluetoothapp.receiver.BluetoothReceiver
import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import java.util.*

/**
 * 项目名称：BluetoothApp
 * 创建人：江心才子
 * 创建时间：2020年4月2日 18:52:26
 * 内容描述：Android蓝牙开发流程实践
开启 扫描 配对 连接 通信
 * 修改说明：
 */
object BlueToothHelper {
    private lateinit var app: Application

    private val mBluetoothAdapter by lazy { BluetoothAdapter.getDefaultAdapter() }
    private val bluetoothReceiver by lazy { BluetoothReceiver() }
    private val scope by lazy { CoroutineScope(Dispatchers.Default) }
    private var socket: BluetoothSocket? = null
    private val parser by lazy { Parser() }
    var callback: BlueToothHelperCallback? = null

    fun initial(app: Application) {
        EventBus.getDefault().register(this)
        this.app = app
        registerBlueToothReceiver()
    }

    private fun registerBlueToothReceiver() {
        app.registerReceiver(
            bluetoothReceiver,
            IntentFilter().apply {
                // 1.监听蓝牙的开启状态
                addAction(BluetoothAdapter.ACTION_STATE_CHANGED)
                // 2.监听蓝牙的连接状态
                addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)
                addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED)
                addAction(BluetoothDevice.ACTION_ACL_CONNECTED)
                // 3.监听蓝牙扫描状态
                addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED)
                addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)
                addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED)
                // 4.发现蓝牙
                addAction(BluetoothDevice.ACTION_FOUND)
            }
        )
    }

    fun start() {
        callback?.connecting()
        scope.launch {
            enable()
            var startDiscovery = startDiscovery()
            repeat(3) {
                if (!startDiscovery) {
                    delay(2000)
                    enable()
                    startDiscovery = startDiscovery()
                    if (startDiscovery) return@repeat
                }
            }
        }
    }

    fun release() {
        app.unregisterReceiver(bluetoothReceiver)
        EventBus.getDefault().unregister(this)
        scope.cancel()
    }

    private fun enable() {
        if (mBluetoothAdapter.isEnabled) return
        val enable = mBluetoothAdapter.enable()
        LogUtil.i("1.开启 $enable")
    }

    private fun startDiscovery(): Boolean {
        if (mBluetoothAdapter.isDiscovering) cancelDiscovery()
        val startDiscovery = mBluetoothAdapter.startDiscovery()
        LogUtil.i("2.扫描 $startDiscovery")
        return startDiscovery
    }

    private fun checkBondedDevices(predicate: (BluetoothDevice) -> Boolean): BluetoothDevice? {
        LogUtil.i("1.1.bondedDevices =  ${mBluetoothAdapter.bondedDevices}")
        return mBluetoothAdapter.bondedDevices.find(predicate)
    }

    private fun cancelDiscovery() {
        val cancelDiscovery = mBluetoothAdapter.cancelDiscovery()
        LogUtil.i("2.取消扫描 $cancelDiscovery")
    }

    private fun connect(device: BluetoothDevice? = null, address: String = "") {
        scope.launch(Dispatchers.IO) {
            device ?: if (address.isEmpty()) throw Throwable("connect方法参数为空")
            LogUtil.i("4.连接...")

            val deviceTemp = device ?: mBluetoothAdapter.getRemoteDevice(address)
            LogUtil.i("${deviceTemp.name}, ${deviceTemp.address}")

            try {
                socket = deviceTemp.createRfcommSocketToServiceRecord(UUID.fromString(UUID4))
                socket?.connect()
                LogUtil.i("4.连接成功")
                withContext(Dispatchers.Main) {
                    callback?.connectSuccess()
                }
                communication()
            } catch (e: Exception) {
                socket?.use {
                    LogUtil.i("4.连接失败 ${e.message}")
                    withContext(Dispatchers.Main) {
                        callback?.connectFailed()
                    }
                }
            }
        }
    }

    /** 通讯 */
    private fun communication() {
        val builder = StringBuilder()
        val list = mutableListOf<Byte>()
        scope.launch(Dispatchers.IO) {
            socket?.inputStream!!.apply {
                var b = read()
                while (b != -1) {
                    parser.parseByte(b.toByte(), callback)
                    try {
                        b = read()
                    } catch (e: Exception) {
                        e.printStackTrace()
                        b = -1
                        withContext(Dispatchers.Main) {
                            this@BlueToothHelper.cancel()
                        }
                    }
                }
            }
        }
    }

    private fun createBond(device: BluetoothDevice? = null, address: String = "") {
        device ?: if (address.isEmpty()) throw Throwable("connect方法参数为空")

        val deviceTemp = device ?: mBluetoothAdapter.getRemoteDevice(address)
        val createBond = deviceTemp.createBond()
        LogUtil.i("3.配对 = $createBond")
    }

    fun cancel() {
        socket?.apply {
            if (!isConnected) return
            LogUtil.i("5.断开连接")
            callback?.disconnect()
            try {
                close()
                socket = null
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    @Subscribe
    fun onBlueStateChange(info: BlueInfo) {
        when (info.status) {
            BlueState.ACTION_DISCOVERY_STARTED -> {
                checkBondedDevices {
                     it.name.startsWith("AX")
//                    "AX0015" == it.name
                }?.let {
                    connect(it)
                    cancelDiscovery()
                }
            }
            BlueState.ACTION_FOUND -> {
                val device = mBluetoothAdapter.getRemoteDevice(info.deviceAddress)
                if ("AX0015" == device.name) {
                    createBond(address = info.deviceAddress)
                    cancelDiscovery()
                }
            }
            BlueState.BOND_BONDED -> {
                connect(address = info.deviceAddress)
            }
            else -> {
            }
        }
    }
}

/*fun ByteArray.bytesToHexString(): String {
    val stringBuilder = StringBuilder()
    forEachIndexed { i, byte ->
        val v: Int = byte.toInt() and 0xFF
        val hv = Integer.toHexString(v)
        if (hv.length < 2) {
            stringBuilder.append("0")
        }
        stringBuilder.append(hv).append(" ")
        val index = i + 1
        if (index % 24 == 0) stringBuilder.append("+\n")
    }
    return stringBuilder.toString()
}*/

/** 通讯 */
/*
private fun communication() {
    val builder = StringBuilder()
    val list = mutableListOf<Byte>()
    BlueToothHelper.scope.launch(Dispatchers.IO) {
        socket?.inputStream!!.apply {
            var bytesCopied: Long = 0
            val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
            var bytes = read(buffer)
            while (bytes >= 0) {
//                out.write(buffer, 0, bytes)
                KLog.i("bytes = $bytes") //通常是290
                if (bytes < buffer.size) {
                    buffer = buffer.take(bytes).toByteArray()
                }
                builder.append(buffer.bytesToHexString())
                builder.append(buffer.bytesToHexString(bytes))
                //一直是0, 这里不需要做非零判断
                KLog.i("available = ${available()}")
                KLog.i(builder)
                builder.clear()

                bytesCopied += bytes
                bytes = read(buffer)
            }
        }
    }
}*/
